﻿using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Ah.Testudin.Engine.Graphics;
using Ah.Testudin.Engine.Graphics.Scenes.SceneNodes.Cameras;

namespace Ah.Testudin.Engine.Physics
{
    public delegate Matrix GetWorldViewDelegate();

    public delegate Matrix GetWorldProjectionDelegate();

    public class BulletDebugDrawer : BulletSharp.IDebugDraw
    {
        #region Private Member Variables

        private readonly ITestudinRenderer _renderer;

        private readonly BasicEffect _effect;

        private readonly GetWorldViewDelegate _getWorldViewDelegate;

        private readonly GetWorldProjectionDelegate _getWorldProjectionDelegate;

        #endregion

        #region Constructors

        public BulletDebugDrawer(
            BasicEffect effect,
            ITestudinRenderer renderer,
            GetWorldViewDelegate getWorldViewDelegate,
            GetWorldProjectionDelegate getWorldProjectionDelegate)
        {
            if (effect == null)
            {
                throw new ArgumentNullException("effect");
            }

            if (renderer == null)
            {
                throw new ArgumentNullException("renderer");
            }

            _effect = effect;

            _renderer = renderer;

            _getWorldViewDelegate = getWorldViewDelegate;

            _getWorldProjectionDelegate = getWorldProjectionDelegate;
        }

        #endregion

        #region IDebugDraw

        public BulletSharp.DebugDrawModes DebugMode { get; set; }

        public void Draw3dText(ref Vector3 location, string textString)
        {
            throw new System.NotImplementedException();
        }

        public void DrawAabb(ref Vector3 from, ref Vector3 to, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawArc(ref Vector3 center, ref Vector3 normal, ref Vector3 axis, float radiusA, float radiusB, float minAngle, float maxAngle, Color color, bool drawSect, float stepDegrees)
        {
            throw new System.NotImplementedException();
        }

        public void DrawArc(ref Vector3 center, ref Vector3 normal, ref Vector3 axis, float radiusA, float radiusB, float minAngle, float maxAngle, Color color, bool drawSect)
        {
            throw new System.NotImplementedException();
        }

        public void DrawBox(
            ref Vector3 fbl, 
            ref Vector3 btr, 
            ref Matrix trans, 
            Color color)
        {
            Vector3 frontBottomLeft = Vector3.Transform(fbl, trans);

            Vector3 backTopRight = Vector3.Transform(btr, trans);

            Vector3 frontTopLeft = new Vector3(
                frontBottomLeft.X,
                backTopRight.Y,
                frontBottomLeft.Z);

            DrawLine(
                ref frontBottomLeft,
                ref frontTopLeft,
                color);

            Vector3 frontTopRight = new Vector3(
                backTopRight.X,
                backTopRight.Y,
                frontBottomLeft.Z);

            DrawLine(
                ref frontTopLeft,
                ref frontTopRight,
                color);

            Vector3 frontBottomRight = new Vector3(
                backTopRight.X,
                frontBottomLeft.Y,
                frontBottomLeft.Z);

            DrawLine(
                ref frontTopRight,
                ref frontBottomRight,
                color);

            DrawLine(
                ref frontBottomRight,
                ref frontBottomLeft,
                color);

            DrawLine(ref frontTopRight, ref backTopRight, color);

            Vector3 backBottomRight = new Vector3(
                frontBottomRight.X,
                frontBottomRight.Y,
                backTopRight.Z);

            DrawLine(ref backTopRight, ref backBottomRight, color);

            DrawLine(ref backBottomRight, ref frontBottomRight, color);

            Vector3 backTopLeft = new Vector3(
                frontTopLeft.X,
                frontTopLeft.Y,
                backTopRight.Z);

            DrawLine(ref backTopRight, ref backTopLeft, color);

            Vector3 backBottomLeft = new Vector3(
                backTopLeft.X,
                frontBottomLeft.Y,
                backTopLeft.Z);

            DrawLine(ref backTopLeft, ref backBottomLeft, color);

            DrawLine(ref backTopLeft, ref frontTopLeft, color);

            DrawLine(ref backBottomLeft, ref frontBottomLeft, color);

            DrawLine(ref backBottomLeft, ref backBottomRight, color);
        }

        public void DrawBox(ref Vector3 bbMin, ref Vector3 bbMax, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawCapsule(float radius, float halfHeight, int upAxis, ref Matrix transform, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawCone(float radius, float height, int upAxis, ref Matrix transform, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawContactPoint(ref Vector3 pointOnB, ref Vector3 normalOnB, float distance, int lifeTime, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawCylinder(float radius, float halfHeight, int upAxis, ref Matrix transform, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawLine(ref Vector3 from, ref Vector3 to, Color color)
        {
            _renderer.RasterizerState = RasterizerState.CullNone;

            _renderer.BlendState = BlendState.Opaque;

            _renderer.DepthStencilState = new DepthStencilState()
            {
                DepthBufferEnable = true
            };

            Matrix worldView = _getWorldViewDelegate();

            _effect.View = _getWorldViewDelegate();

            _effect.Projection = _getWorldProjectionDelegate();

            _effect.World = Matrix.Identity;

            foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
            {
                pass.Apply();
            }

            _renderer.DrawUserIndexedPrimitives<VertexPositionColor>(
                PrimitiveType.LineList,
                new VertexPositionColor[2]
                {
                    new VertexPositionColor(
                        from,
                        color),
                    new VertexPositionColor(
                        to,
                        color)
                },
                0,
                2,
                new int[2] { 0, 1 },
                0,
                1);
        }

        public void DrawLine(ref Vector3 from, ref Vector3 to, Color fromColor, Color toColor)
        {
            throw new System.NotImplementedException();
        }

        public void DrawPlane(ref Vector3 planeNormal, float planeConst, ref Matrix transform, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawSphere(ref Vector3 p, float radius, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawSphere(float radius, ref Matrix transform, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawSpherePatch(ref Vector3 center, ref Vector3 up, ref Vector3 axis, float radius, float minTh, float maxTh, float minPs, float maxPs, Color color, float stepDegrees)
        {
            throw new System.NotImplementedException();
        }

        public void DrawSpherePatch(ref Vector3 center, ref Vector3 up, ref Vector3 axis, float radius, float minTh, float maxTh, float minPs, float maxPs, Color color)
        {
            throw new System.NotImplementedException();
        }

        public void DrawTransform(
            ref Matrix transform, 
            float orthoLen)
        {
            
        }

        public void DrawTriangle(ref Vector3 v0, ref Vector3 v1, ref Vector3 v2, Color color, float __unnamed004)
        {
            throw new System.NotImplementedException();
        }

        public void DrawTriangle(ref Vector3 v0, ref Vector3 v1, ref Vector3 v2, ref Vector3 __unnamed003, ref Vector3 __unnamed004, ref Vector3 __unnamed005, Color color, float alpha)
        {
            throw new System.NotImplementedException();
        }

        public void ReportErrorWarning(string warningString)
        {
            throw new System.NotImplementedException();
        }

        #endregion
    }
}
